﻿using FileManagerSystem.DbInfos;
using FileManagerSystem.Extend;
using FileManagerSystem.Helper;
using FileManagerSystem.Models;
using FileManagerSystem.Service;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace FileManagerSystem.Controllers
{
    /// <summary>
    /// 文件仓库管理系统
    /// </summary>
    public class FileManagerController : ApiBaseController
    {
        /// <summary>
        /// 原始文件Service对象
        /// </summary>
        [Autowired]
        private IFileService _fileService { get; set; }

        /// <summary>
        /// 映射文件Service对象
        /// </summary>
        [Autowired]
        private IReflectFileService _reflectfileService { get; set; }

        /// <summary>
        /// 映射目录Service对象
        /// </summary>
        [Autowired]
        private IDirectoryService _directoryService { get; set; }

        #region 文件相关
        /// <summary>
        /// 查询所有原始文件
        /// </summary>
        /// <param name="search">查询条件</param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetAllSourceFileInfo(string search, int page = 0, int size = int.MaxValue)
        {
            Expression<Func<FileInf, bool>> whereFunc = x => true;
            if (!search.IsNullOrWhiteSpace())
            {
                whereFunc = whereFunc.And(x => x.Name.Contains(search));
            }
            var result = await _fileService.FindAllToPage(whereFunc, page, size);
            //TODO：处理文件信息，获取存储路径等信息
            return this.Json(result);
        }

        /// <summary>
        /// 查询所有映射文件（一般文件查询均是从此查询的，包括下载时，因为没有io存储的等待，所以这个表是非常快的）
        /// </summary>
        /// <param name="search">查询条件</param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetAllReflectFileInfo(string search, int page = 0, int size = int.MaxValue)
        {
            Expression<Func<ReflectFileInf, bool>> whereFunc = x => true;
            if (!search.IsNullOrWhiteSpace())
            {
                whereFunc = whereFunc.And(x => x.Name.Contains(search));
            }
            var result = await _reflectfileService.FindAllToPage(whereFunc, page, size);
            return this.Json(result);
        }

        ///// <summary>
        ///// 获取多个文件的信息
        ///// </summary>
        ///// <param name="guids">多个文件的guid集合</param>
        ///// <returns></returns>
        //[HttpPost]
        //public async Task<IActionResult> GetFileInfos(List<string> guids)
        //{
        //    Stopwatch sw = new Stopwatch();
        //    sw.Start();
        //    var result = new List<CompleteFileResult>();
        //    foreach (var guid in guids)
        //    {
        //        if (!Guid.TryParse(guid, out Guid id))
        //            throw new Exception($"传入的guid不合法：{guid}");

        //        var reflectFile = await _reflectfileService.FindOne(x => x.Id == id);
        //        if (reflectFile == null)
        //            throw new Exception("未找到映射文件");

        //        var sourceFile = await _fileService.FindOne(x => x.Id == reflectFile.PId);
        //        if (sourceFile == null)
        //            throw new Exception("未找到原始文件");

        //        var file = new CompleteFileResult()
        //        {
        //            Id = reflectFile.Id,
        //            AbstractDirPath = reflectFile.AbstractDirPath,
        //            AbstractTopDirGuid = reflectFile.AbstractTopDirGuid,
        //            Extension = reflectFile.Extension,
        //            Keep = reflectFile.Keep,
        //            Name = reflectFile.Name,
        //            UploadTime = reflectFile.UploadTime,
        //            PId = sourceFile.Id,
        //            DirPath = sourceFile.DirPath,
        //            FileSize = sourceFile.FileSize,
        //            MimeType = sourceFile.MimeType,
        //            Md5 = sourceFile.Md5,
        //        };
        //        result.Add(file);
        //    }

        //    sw.Stop();
        //    Console.WriteLine("单循环耗时：" + sw.ElapsedMilliseconds);
        //    return Json(result);
        //}

        /// <summary>
        /// 获取多个文件的信息
        /// </summary>
        /// <param name="guids">多个文件的guid集合</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> GetFileInfos(List<string> guids)
        {
            var result = new List<SimpleFileInfo>();
            var listGuid = new List<Guid>();

            foreach (var guid in guids)
            {
                if (!Guid.TryParse(guid, out Guid id))
                    throw new Exception($"传入的guid不合法：{guid}");
                listGuid.Add(id);
            }

            var reflectFiles = await _reflectfileService.FindAll(x => listGuid.Contains(x.Id));
            foreach (var reflectFile in reflectFiles)
            {
                if (reflectFile == null)
                    throw new Exception("未找到映射文件");
                var sourceFile = await _fileService.FindOne(x => x.Id == reflectFile.PId);
                if (sourceFile == null)
                    throw new Exception("未找到原始文件");
                var file = new SimpleFileInfo()
                {
                    Id = reflectFile.Id,
                    Name = reflectFile.Name,
                    Extension = reflectFile.Extension,
                    FileSize = FileOperateHelper.GetFileSize(sourceFile.FileSize),
                };
                result.Add(file);
            }
            return Json(result);
        }
        /// <summary>
        /// 获取单文件信息
        /// </summary>
        /// <param name="guid">文件唯一标识</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetFileInfo(string guid)
        {
            if (!Guid.TryParse(guid, out Guid id))
                throw new Exception($"传入的guid不合法：{guid}");

            var reflectFile = await _reflectfileService.FindOne(x => x.Id == id);
            if (reflectFile == null)
                throw new Exception("未找到映射文件");
            var sourceFile = await _fileService.FindOne(x => x.Id == reflectFile.PId);
            if (sourceFile == null)
                throw new Exception("未找到原始文件");
            var result = new CompleteFileResult()
            {
                Id = reflectFile.Id,
                AbstractDirPath = reflectFile.AbstractDirPath,
                AbstractTopDirGuid = reflectFile.AbstractTopDirGuid,
                Extension = reflectFile.Extension,
                Keep = reflectFile.Keep,
                Name = reflectFile.Name,
                UploadTime = reflectFile.UploadTime,
                PId = sourceFile.Id,
                DirPath = sourceFile.DirPath,
                FileSize = sourceFile.FileSize,
                MimeType = sourceFile.MimeType,
                Md5 = sourceFile.Md5,
            };
            return Json(result);
        }

        /// <summary>
        /// 清空所有数据 数据库 + 真实文件
        /// TODO：正式上线后会去掉此接口
        /// </summary>
        /// <returns></returns>
        [HttpDelete]
        public async Task<IActionResult> DeleteAllData()
        {
            var result1 = await _fileService.DeleteMany(x => true);
            var result2 = await _reflectfileService.DeleteMany(x => true);
            var result3 = await _directoryService.DeleteMany(x => true);
            var finalDir = Path.Combine("StaticFiles", "Files");
            var finalDir1 = Path.Combine("StaticFiles", "TempArchiceFiles");
            var finalDir2 = Path.Combine("StaticFiles", "TempReadFiles");
            var finalDir3 = Path.Combine("StaticFiles", "TempFiles");

#pragma warning disable CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
            FileOperateHelper.TryDeleteDirectory(finalDir, true);//异步删除，无需等待
            FileOperateHelper.TryDeleteDirectory(finalDir1, true);//异步删除，无需等待
            FileOperateHelper.TryDeleteDirectory(finalDir2, true);//异步删除，无需等待
            FileOperateHelper.TryDeleteDirectory(finalDir3, true);//异步删除，无需等待
#pragma warning restore CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法

            return this.Json(new { result1, result2, result3 });
        }

        /// <summary>
        /// 单条目删除测试
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        [HttpDelete]
        public async Task<IActionResult> Delete(string guid)
        {
            if (!Guid.TryParse(guid, out Guid id))
                throw new Exception($"传入的guid不合法：{guid}");

            bool result = false;

            //  注意映射文件删除和普通文件删除不一样，需区分处理，映射文件删除仅删除其对原始文件的引用实际上
            var reflectfileInfo = await _reflectfileService.FindOne(x => x.Id == id);
            if (reflectfileInfo == null)//映射表中找不到文件，去原始表中查找试试
            {
                var fileInfo = await _fileService.FindOne(x => x.Id == id);
                if (fileInfo == null)
                    throw new Exception("未找到文件");
                result = await _fileService.Delete(id);//如果找到，先删数据库信息，再删实际文件
                //尝试清除该实际文件
                var fileRealPath = Path.Combine(fileInfo.DirPath, fileInfo.Id.ToString() + fileInfo.Extension);//真实原文件路径（GUID名称+格式后缀）
#pragma warning disable CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
                FileOperateHelper.TryDeleteFile(fileRealPath);//异步删除，无需等待
#pragma warning restore CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
            }
            else
            {
                result = await _reflectfileService.Delete(id);
            }
            return this.Json(result);
        }

        #endregion
    }
}
